package com.css.util;


import com.css.attachment.entity.ParsingResult;
import com.css.enums.GeomTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.referencing.CRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.filter.Filter;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Dbj
 * @date 2024年08月30日  13:47
 */
@Slf4j
public class ShpAnalyticUtil {

    /**
     * 读取prj文件内容
     */
    public static String readPRJ(String path) {
        StringBuffer result = new StringBuffer();
        File file = new File(path);
        if (!file.exists()) {
            return "";
        }
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                result.append(tempString);
                log.info(tempString);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.toString();
    }
    /**
     * 校验是否为2000坐标系
     */
    public static String checkCoordinateSystem(String prj) {
        String strwktmercator = readPRJ(prj);
        if ("".equals(strwktmercator)) {
            return "";
        }
        CoordinateReferenceSystem sourceTarget = null;
        try {
            sourceTarget = CRS.parseWKT(strwktmercator);
        } catch (FactoryException e) {
            e.printStackTrace();
            log.error(prj + ": 解析错误!");
        }
        String name = sourceTarget.getName().toString();
//        if (name.indexOf("CGCS2000") != -1 || name.indexOf("cgcs2000") != -1 || name.indexOf("Geodetic_Coordinate_System_2000") != -1 ||
//                name.indexOf("Geodetic Coordinate System 2000") != -1) return true;
        if (name.contains("CGCS2000") ||
                name.contains("cgcs2000") ||
                name.contains("Geodetic_Coordinate_System_2000") ){
            return "4490";
        }
        if (name.contains("WGS_1984")){
            return "4326";
        }
        return "";
    }

    public static String checkGeomTypeOf(Object obj, GeomTypeEnum... geomTypes) throws Exception {
        if (obj == null) {
            throw new Exception("空间数据不能为空，请检查文件再次上传");
        }
        String val = obj.toString();
        boolean flag = false;
        for (GeomTypeEnum geomType : geomTypes) {
            if (val.contains(geomType.name())) {
                flag = true;
            }
        }
        if (!flag) {
            throw new Exception("空间数据类型有误，请上传" + StringUtils.join(Arrays.stream(geomTypes).map(GeomTypeEnum::getDescByEnum).collect(Collectors.toList()), "或") + "类型的空间数据");
        }
        return val;
    }
    /**
     * 解析shp文件
     *
     * @param prj .prj文件的真实地址
     * @param cpg .cpg文件的真实地址
     * @param shp .shp文件的真实地址
     * @return
     */
    public static ParsingResult analytic(String prj, String cpg, String shp) {
        log.info("进行shp文件解析 >> {}", shp);
        //校验是否为2000或WGS_1984坐标系
        String code = "";
        if(StringUtils.isBlank(prj)){
            code = "4490";
        }else{
            code = checkCoordinateSystem(prj);
            if("".equals(code)){
                code = "4490";
            }
            if (!"4490".equals(code) && !"4326".equals(code)) {
                log.info(new Date() + "-----------校验失败.请上传正确的坐标系数据及.prj文件.");
                return ParsingResult.shpData("请上传正确的坐标系数据及.prj文件", null);
            }
        }
        //读取cpg文件编码
        String codeType = "GBK".equals(cpg) || "UTF-8".equals(cpg)?cpg:readCPG(cpg);
//        String codeType = cpg;
        SimpleFeatureIterator iters = null;
        ArrayList<List<Object>> lists = new ArrayList<>();
        try {
            //获取shp数据
            SimpleFeatureCollection colls1 = readShp(shp, null, codeType);
            iters = colls1.features();
            int i = 0;
            while (iters.hasNext()) {
                SimpleFeature next = iters.next();
                List<Object> attributes = next.getAttributes();
                int size = attributes.size();
                //保存shp文件编码 是4490还是4326
                attributes.add(size,code);
                log.debug("解析第{}条数据:{}", ++i, attributes);
                lists.add(attributes);
            }
            if (lists.size() == 0) {
                return ParsingResult.shpData("解析失败shp文件中没有数据", lists);
            }
        } finally {
            if (iters != null) {
                iters.close();
            }
        }
        log.info("shp文件解析成功 >> {}", shp);
        return ParsingResult.shpData("ok", lists);
    }

    public static ParsingResult analytic(String cpg, String shp) {
        log.info("进行shp文件解析 >> {}", shp);
        //读取cpg文件编码
        //String codeType = readCPG(cpg);
        String codeType = cpg;
        SimpleFeatureIterator iters = null;
        ArrayList<List<Object>> lists = new ArrayList<>();
        try {
            //获取shp数据
            SimpleFeatureCollection colls1 = readShp(shp, null, codeType);
            iters = colls1.features();
            int i = 0;
            while (iters.hasNext()) {
                SimpleFeature next = iters.next();
                List<Object> attributes = next.getAttributes();
                log.debug("解析第{}条数据:{}", ++i, attributes);
                lists.add(attributes);
            }
            if (lists.size() == 0) {
                return ParsingResult.shpData("解析失败shp文件中没有数据", lists);
            }
        } finally {
            if (iters != null) {
                iters.close();
            }
        }
        log.info("shp文件解析成功 >> {}", shp);
        return ParsingResult.shpData("ok", lists);
    }

    /**
     * 读取cpg文件编码
     */
    public static String readCPG(String path) {
        String codeType = "UTF-8";
        StringBuffer result = new StringBuffer();
        File file = new File(path);
        if (!file.exists()) return "";
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                result.append(tempString);
                System.out.println(tempString);
            }
            reader.close();
            //返回结果
            codeType = result.toString();
            //转换大写
            codeType = codeType.toUpperCase();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return codeType;
    }

    public static SimpleFeatureCollection readShp(String path, Filter filter, String codeType) {
        SimpleFeatureSource featureSource = readStoreByShp(path, codeType);
        if (featureSource == null) return null;
        try {
            return filter != null ? featureSource.getFeatures(filter) : featureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static SimpleFeatureSource readStoreByShp(String path, String codeType) {
        File file = new File(path);
        FileDataStore store;
        SimpleFeatureSource featureSource = null;
        try {
            store = FileDataStoreFinder.getDataStore(file);
            ((ShapefileDataStore) store).setCharset(Charset.forName(codeType));
            featureSource = store.getFeatureSource();
            store.dispose();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return featureSource;
    }

    public static String getStringVal(Object text, String msg, boolean must) throws Exception {
        if (must) {
            return getStringVal4Must(text, msg);
        } else {
            return getStringValNotMust(text);
        }
    }

    private static String getStringVal4Must(Object text, String msg) throws Exception {
        if (text == null || StringUtils.isBlank(text.toString())) {
            throw new Exception(msg + "不能为空");
        }
        return text.toString();
    }

    public static String getStringValNotMust(Object text) throws Exception {
        if (text == null || StringUtils.isBlank(text.toString())) {
            return null;
        }
        return text.toString();
    }
}
